﻿using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq.Expressions;
using System.Web.Mvc.Html;
using System.Web.Routing;
using TSharp.Core.Util;

namespace System.Web.Mvc
{
    /// <summary>
    ///     这是一个Form生成的扩展类
    ///     <para>
    ///         是用于解决原BeginForm&lt;T&gt;生成的代码会再使用Jquery客户端验证时发生脚本错误的问题。
    ///     </para>
    ///     <para>2010/10/28</para>
    ///     <para>TANGJINGBO</para>
    ///     <author>tangjingbo</author>
    /// </summary>
    public static class FormExtensions
    {
        private static readonly object _lastFormNumKey = new object();

        /// <summary>
        ///     创建Form，需使用Dispose来生成结束标记
        /// </summary>
        /// <typeparam name="TController">The type of the controller.</typeparam>
        /// <param name="helper">被扩展的HtmlHelper实例</param>
        /// <param name="action">Form提交的action的lambda表示方式</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification =
                "This is an Extension Method which allows the user to provide a strongly-typed argument via Expression")
        ]
        public static MvcForm BeginFormA<TController>(this HtmlHelper helper, Expression<Action<TController>> action)
            where TController : Controller
        {
            return BeginFormA(helper, action, FormMethod.Post, null);
        }

        /// <summary>
        ///     创建Form，需使用Dispose来生成结束标记
        /// </summary>
        /// <typeparam name="TController">The type of the controller.</typeparam>
        /// <param name="helper">被扩展的HtmlHelper实例</param>
        /// <param name="action">Form提交的action的lambda表示方式</param>
        /// <param name="method">Form提交方式，Get或者Post</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification =
                "This is an Extension Method which allows the user to provide a strongly-typed argument via Expression")
        ]
        public static MvcForm BeginFormA<TController>(this HtmlHelper helper, Expression<Action<TController>> action,
                                                      FormMethod method) where TController : Controller
        {
            return BeginFormA(helper, action, method, null);
        }

        /// <summary>
        ///     创建开始Form，需使用Dispose来生成结束标记
        /// </summary>
        /// <typeparam name="TController">The type of the controller.</typeparam>
        /// <param name="helper">被扩展的HtmlHelper实例</param>
        /// <param name="action">Form提交的action的lambda表示方式</param>
        /// <param name="method">Form提交方式，Get或者Post</param>
        /// <param name="htmlAttributes">The HTML attributes.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification =
                "This is an Extension Method which allows the user to provide a strongly-typed argument via Expression")
        ]
        public static MvcForm BeginFormA<TController>(this HtmlHelper helper, Expression<Action<TController>> action,
                                                      FormMethod method, object htmlAttributes)
            where TController : Controller
        {
            return BeginFormA(helper, action, method, new RouteValueDictionary(htmlAttributes));
        }


        /// <summary>
        ///     Increments the form count.
        /// </summary>
        /// <param name="items">The items.</param>
        /// <returns></returns>
        private static int IncrementFormCount(IDictionary items)
        {
            object lastFormNum = items[_lastFormNumKey];
            int newFormNum = (lastFormNum != null) ? ((int) lastFormNum) + 1 : 0;
            items[_lastFormNumKey] = newFormNum;
            return newFormNum;
        }

        /// <summary>
        ///     创建开始Form，需使用Dispose来生成结束标记
        /// </summary>
        /// <typeparam name="TController">The type of the controller.</typeparam>
        /// <param name="helper">被扩展的HtmlHelper实例</param>
        /// <param name="action">Form提交的action的lambda表示方式</param>
        /// <param name="method">Form提交方式，Get或者Post。</param>
        /// <param name="htmlAttributes">The HTML attributes.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
            Justification =
                "This is an Extension Method which allows the user to provide a strongly-typed argument via Expression")
        ]
        public static MvcForm BeginFormA<TController>(this HtmlHelper helper, Expression<Action<TController>> action,
                                                      FormMethod method, IDictionary<string, object> htmlAttributes)
            where TController : Controller
        {
            var tagBuilder = new TagBuilder("form");
            if (helper.ViewContext.ClientValidationEnabled)
            {
                // forms must have an ID for client validation
                // 是必须有个id，可是不能仅使用自动生成 by tangjingbo @2010-10-28
                string formId = htmlAttributes["id"].ToStringObject();
                if (string.IsNullOrEmpty(formId))
                {
                    int formNum = IncrementFormCount(helper.ViewContext.HttpContext.Items);
                    formId = String.Format(CultureInfo.InvariantCulture, "form{0}", formNum);
                }
                tagBuilder.GenerateId(formId);
            }
            tagBuilder.MergeAttributes(htmlAttributes);
            string formAction = Microsoft.Web.Mvc.LinkExtensions.BuildUrlFromExpression(helper, action);
            tagBuilder.MergeAttribute("action", formAction);
            tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method));

            helper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
            var theForm = new MvcForm(helper.ViewContext);

            if (helper.ViewContext.ClientValidationEnabled)
            {
                helper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"];
            }

            return theForm;
        }
    }
}